-
Notifications
You must be signed in to change notification settings - Fork 467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add OAuth #879
Add OAuth #879
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for taking this on already CJ!
I left some high level comments! Since this is something I'm less familiar with though I will defer to Brandur on doing the thorough review
15379aa
to
b396ce7
Compare
Excited to get to use this soon! Is there a rough timeline for when this can get in? |
ca17387
to
3c92581
Compare
Hmm. tests are passing locally... Investigating |
Odd. I didn't have |
Lint's in Make, but it's a separate step ( |
556fd8d
to
ca72804
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome @cjavilla-stripe!! This is a feature that we've wanted for a long time, but been too lazy to do :) Thank you.
I left quite a few comments here, but in general it's all pretty cosmetic stuff with quite a few duplicates, so it shouldn't be anywhere near as bad as it seems.
Sorry about the delay on review — I think Remi and I both assumed the other person was going to do it, haha. Once you've made changes, feel free to bump it back to me.
ptal @cjavilla-stripe
form/form.go
Outdated
@@ -498,6 +499,21 @@ func (f *Values) Encode() string { | |||
return buf.String() | |||
} | |||
|
|||
// EncodeValues encodes only the values into “URL encoded” form | |||
// ("bar=baz&foo=quux") so that we can have keys like `stripe_user[email]=test` | |||
func (f *Values) EncodeValues() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should have two methods that do so close to the same thing here.
A couple suggestions:
- Did you double-check what happens if you change
Encode
to notQueryEscape
the key? I can't remember if there's a good reason that we this off hand. - Otherwise, we can just do the
QueryEscape
and then change the encoded square backets back to square brackets. This is what stripe-ruby does:
def self.url_encode(key)
CGI.escape(key.to_s).
# Don't use strict form encoding by changing the square bracket control
# characters back to their literals. This is fine by the server, and
# makes these parameter strings easier to read.
gsub("%5B", "[").gsub("%5D", "]")
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that not escaping the key would be considered a breaking change, so opted initially for a second encode method, but I think we control the keys here so not escaping the key seems fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solved it this way. seems to work well :)
oauth/client.go
Outdated
} | ||
if stripe.StringValue(params.GrantType) == "" { | ||
params.GrantType = stripe.String("authorization_code") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOC, is there some particular rationale behind providing a parameter default here?
It may be a little more convenient I suppose, but I think our normal convention is just allowing the API request to fail the first time and signal back that grant_type=authorization_code
should have been passed, at which point the user just corrects their implementation. It's one extra step, but they probably won't ever make the mistake again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it was all about convenience. Trying to make it so that users of this can pass some basics and we send sensible defaults.
ca72804
to
d9ab7ec
Compare
Thanks for the review and your patience, @brandur-stripe :) |
@nirajjayantbolt hopefully soon! sorry for the delay 😄 |
stripe.go
Outdated
// ClientID is the Stripe Client ID used by default for OAuth requests. | ||
// Relevant OAuth parameter types can also be initialized with a specific | ||
// ClientID that will take precidence over this global ClientID. | ||
var ClientID string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@remi-stripe Any opinion on having a global ClientID
versus just requiring that one be passed with parameters? I don't feel too strongly about it, but in general would prefer to avoid globals where possible, so I'd lean toward the latter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We chatted via slack and he agreed with you, so I've removed :)
Oops, and realized I forgot to answer your original questions:
Definitely big-ish, but most of our OAuth implementations in other languages came in as part of one big PR, so it's not that unusual.
Yeah, it was best to just follow the convention and use pointers, so you did the right thing. The reason for pointer is that because variables in Go by default get their zero value (so a string defaults to type MyParams struct {
MyStr string
}
// These were initialized quite differently, but they look
// identical in Go because `MyStr` defaults to ""
p1 := &MyParams{}
p2 := &MyParams{MyStr: ""} This doesn't make that much of a difference a lot of the time, but there are a couple places where the zero values are important. For example, we might want to explicitly set a string in the API to an empty string to empty it, or a boolean in the API to a The pointers are all
Yeah, what you did there seems sane to me. Thanks for testing! |
oauth.go
Outdated
Currency *string `form:"currency"` | ||
DOBDay *uint64 `form:"dob_day"` | ||
DOBMonth *uint64 `form:"dob_month"` | ||
DOBYear *uint64 `form:"dob_year"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And oops, actually if you wouldn't mind, these should be *int64
actually. They can't be negative so technically uint64
would be a better fit, but at one point we just decided to just go with int64
everywhere by convention — in practice we'll never get to numbers high enough that we need the extra range uint64
gets us, and using int64
gives us some forward compatibility in case a field that currently doesn't allow negative numbers allows them in the future.
a0e49ad
to
6f40d03
Compare
Thanks for that explanation about our pointer use, @brandur-stripe. Remi also shared that with me and seeing those examples really drives it home. I think there are only two major things that need review:
|
Thanks for changing! I was thinking about it some more, and I think this is definitely closer to the path we want. Having a single unified error object for API or OAuth is how it works in stripe-dotnet already [1], and how it's being proposed for stripe-ruby as well [2]. I think it's a little janky that we have to do that two-phase fallback for deserializing an error object (although definitely not the worse thing, and the comment helps a lot). Did you consider alternative a custom Anyway, sorry that this is turning into more work than you probably expected :) The good news is that I think we're pretty close at this point. [1] https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/StripeError.cs#L88-L90 |
One pitfall that I can see possibly happening is that the user doesn't have control anymore over whether the parameter is sent. Say they purposely didn't want to send a particular parameter, they now no longer have a great way to do that (they could do |
e9b2c0b
to
9f0d44d
Compare
Removed the remaining defaults for unspecified values, removed the global ClientID, and took another swag at unmarshaling the error data by forking based on the BackendImplementation type. |
a.OrderReturns = &orderreturn.Client{B: backends.API, Key: key} | ||
a.Orders = &order.Client{B: backends.API, Key: key} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing :)
|
||
// OAuth specific Error properties. Named OAuthError because of name conflict. | ||
OAuthError string `json:"error,omitempty"` | ||
OAuthErrorDescription string `json:"error_description,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually like the "OAuth" prefix anyway — it makes it harder to use these outside of an OAuth context by accident (it's clear they're specifically for OAuth and nothing else).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was actually required because we use Error as a method on this object elsewhere.
State: stripe.String("NV"), | ||
StreetAddress: stripe.String("123 main"), | ||
URL: stripe.String("http://example.com"), | ||
Zip: stripe.String("12345"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized that "Zip" is actually an acronym (Zone Improvement Plan) and probably should've been "ZIP" instead. Don't change it though because we've already got the "Zip" convention in some fields elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Yeah tried to follow convention :)
@cjavilla-stripe New changes look great! Would you mind squashing this down? After that I think we're pretty much good to go. @remi-stripe This looks ready to me. Do you want to take a pass for yourself before we go to release? |
bb8e843
to
3046fbf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squashed and made those final minor adjustments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ptal @cjavilla-stripe Just a couple last-minute comments here, but after those are fixed I think we're good to ship this. Thanks!
oauth/client_test.go
Outdated
// RoundTripFunc. | ||
type RoundTripFunc func(req *http.Request) *http.Response | ||
|
||
// RoundTrip. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And same with this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexported.
oauth/client_test.go
Outdated
func TestNewOAuthToken(t *testing.T) { | ||
stripe.Key = "sk_123" | ||
|
||
// stripe-mock doesn't support connect URL's so this stubs out the server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe consider changing all instances of "URL's" to "URLs"? I Googled and there's no clear answer for the correct way to handle these (sources vary), but my feeling is that the apostrophe-less version is generally preferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated these instances.
3046fbf
to
f796999
Compare
Thanks for the thorough review, @brandur-stripe! :) |
Excellent!! Thank you again CJ! |
Released as 61.23.0. |
🎉 |
r? @remi-stripe
Looking for some feedback:
Here's a sample echo server that uses this successfully: